/**
 * 
 */
package gui.controller;

import exceptions.ValidRangeFormatException;
import gui.view.AttributeTableModel;
import gui.view.AttributesPanel;
import gui.view.EngineMain;
import interfaces.IMeasure;
import interfaces.IRange;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;

import javax.swing.JOptionPane;
import javax.swing.table.DefaultTableModel;

import massDistribution.ContinueMeasure;
import massDistribution.DiscreteMeasure;
import massDistribution.MeasuredAttribute;
import massDistribution.Metric;
import massDistribution.MetricType;

import stubs.RangeParser;
import utilities.TrustEngineUtility;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;

/**
 * @author Elisa Costante
 * 
 */
public class AttributePanelListener implements ActionListener {

	private AttributesPanel panel;
	private final static String newline = "\n";
	private Hashtable<String, MeasuredAttribute> trustAttributes = new Hashtable<String, MeasuredAttribute>();
	private MeasuredAttribute currentNewAttribute;

	public AttributePanelListener(AttributesPanel panel) {
		this.panel = panel;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
	 */
	@Override
	public void actionPerformed(ActionEvent e) {
		// Event associed to the Add button

		if (e.getActionCommand().equalsIgnoreCase("add")) {
			addAction();
		} else if (e.getActionCommand().equalsIgnoreCase("remove")) {
			removeAction();
		} else if (e.getActionCommand().equalsIgnoreCase("load")) {
			File fileChoose = CustomizedFileChooser.getFileToOpen(panel);
			if (fileChoose != null) {
				loadFromXMLFile(fileChoose);
			} else {
				JOptionPane.showMessageDialog(panel,
						"Load not accomplished correctly");
			}

		} else if (e.getActionCommand().equalsIgnoreCase("save")) {
			File fileChoose = CustomizedFileChooser.getFileToSave(panel);
			if (fileChoose != null) {
				saveInXMLFile(fileChoose);
				JOptionPane
						.showMessageDialog(panel, "File saved with success!");

			} else {
				JOptionPane.showMessageDialog(panel,
						"Save action not accomplished correctly");
			}

		} else if (e.getActionCommand().equalsIgnoreCase("ok")) {
			okAction();
		}

	}

	/**
	 * 
	 */
	private void okAction() {

		IMeasure bestCase = null;
		IMeasure worstCase = null;
		IMeasure mediumCase = null;

		// Read the attribute Best, Medium and worst case
		if (currentNewAttribute.getMetric().getType()
				.equals(MetricType.INTEGER)
				|| currentNewAttribute.getMetric().getType().equals(
						MetricType.REAL)) {
			// Read the continuous Best, Worst and Medium Case
			Comparable<?> worst = (Comparable<?>) panel.getWorstCaseCombo()
					.getSelectedItem();
			worstCase = new ContinueMeasure(worst);
			Comparable<?> best = (Comparable<?>) panel.getBestCaseCombo()
					.getSelectedItem();
			bestCase = new ContinueMeasure(best);

			// Set the medium Case
			String mediumString = panel.getMediumCaseTxtField().getText();
			if (mediumString != null && !mediumString.equalsIgnoreCase("")
					&& TrustEngineUtility.isANumber(mediumString)) {
				if (currentNewAttribute.getMetric().getType().equals(
						MetricType.INTEGER)) {
					Comparable mediumInt = (Comparable) Integer
							.parseInt(mediumString);
					mediumCase = new ContinueMeasure(mediumInt);
				} else {
					Comparable mediumDouble = (Comparable) Double
							.parseDouble(mediumString);
					mediumCase = new ContinueMeasure(mediumDouble);
				}
			} else {
				JOptionPane.showMessageDialog(panel,
						"You have to insert a valid Medium Case");
			}
		} else {
			// Discrete Case
			Object worst = (String) panel.getWorstCaseCombo().getSelectedItem();
			worstCase = new DiscreteMeasure(worst);

			String mediumSTR = panel.getMediumCaseTxtField().getText();

			mediumCase = new DiscreteMeasure(mediumSTR);

			Object best = (String) panel.getBestCaseCombo().getSelectedItem();
			bestCase = new DiscreteMeasure(best);

		}

		Metric metric = currentNewAttribute.getMetric();

		if (metric.isMeasureValidForTheMetric(bestCase)
				&& metric.isMeasureValidForTheMetric(mediumCase)
				&& metric.isMeasureValidForTheMetric(worstCase)) {
			// Set the attribute Best and worst case
			metric.setBestCase(bestCase);
			metric.setMediumCase(mediumCase);
			metric.setWorstCase(worstCase);
			currentNewAttribute.setMetric(metric);

			// add the attribute to the table
			addAttributeToTable(panel.getAttributeTableModel(),
					currentNewAttribute);

			// Add the ATTRIBUTE to the list
			trustAttributes.put(currentNewAttribute.getIdentifier(),
					currentNewAttribute);
			panel.getFrame().setAttributeList(trustAttributes);
			// Enable the left panel.
			panel.getBestWorstPanel().setVisible(false);

			EngineMain.setEnabledtPanel(panel.getLeftPanel(), true);

		} else {
			JOptionPane.showMessageDialog(panel,
					"The value inserted are not valid. Please Try again.");
		}

	}

	/**
	 * Save the list of attributes in the <code>filename</code> .xml
	 * 
	 * @param fileChoose
	 */
	private void saveInXMLFile(File fileChoose) {
		// Add the Attribue to an XMLFIle

		XStream xs = new XStream();

		// Write to a file in the file system
		try {
			FileOutputStream fs = new FileOutputStream(fileChoose);
			xs.toXML(trustAttributes, fs);
		} catch (FileNotFoundException e1) {
			e1.printStackTrace();
		}
	}

	/**
	 * Load the list of Attributes from the <code>filename</code> .xml file.
	 * 
	 * @param file
	 */
	@SuppressWarnings("unchecked")
	public void loadFromXMLFile(File file) {
		XStream xs = new XStream(new DomDriver());
		trustAttributes = new Hashtable<String, MeasuredAttribute>();

		try {
			FileInputStream fis = new FileInputStream(file);
			trustAttributes = (Hashtable<String, MeasuredAttribute>) xs
					.fromXML(fis);

			// Set the list
			panel.getFrame().setAttributeList(trustAttributes);

			// shows the attributes
			populateTable();

		} catch (FileNotFoundException ex) {
			ex.printStackTrace();
		}

	}

	/**
	 * Add a list of Attribute tot the table
	 */
	private void populateTable() {
		DefaultTableModel tableModel = new AttributeTableModel();
		tableModel = new DefaultTableModel(new String[] { "Attribute Name",
				"Metric Name", "Metric Type", "Valid Ranges" }, 0);
		Enumeration<MeasuredAttribute> enumeration = trustAttributes.elements();
		while (enumeration.hasMoreElements()) {
			MeasuredAttribute qTrustAttribute = (MeasuredAttribute) enumeration
					.nextElement();
			addAttributeToTable(tableModel, qTrustAttribute);

		}
		panel.setAllAttributeTable(tableModel);

	}

	/**
	 * @param newAttribute
	 */
	private void addAttributeToTable(DefaultTableModel model,
			MeasuredAttribute newAttribute) {
		model.addRow(new String[] { newAttribute.getIdentifier(),
				newAttribute.getMetric().getName(),
				newAttribute.getMetric().getType().getName(),
				newAttribute.getMetric().getValidRanges().toString() });
	}

	/**
	 * 
	 */
	private void removeAction() {
		int selectedRow = panel.getAllAttributeTable().getSelectedRow();

		int selectedColumn = 0;
		String identifier = (String) panel.getAttributeTableModel().getValueAt(
				selectedRow, selectedColumn);
		if (trustAttributes.size() > 0
				&& trustAttributes.containsKey(identifier)) {
			trustAttributes.remove(identifier);
			panel.getAttributeTableModel().removeRow(selectedRow);

		}

	}

	/**
	 * 
	 */
	private void addAction() {
		String attributeName = panel.getAttributeNameTxtField().getText();

		// Attribute to
		// the hashTable
		if (trustAttributes.get(attributeName) == null) {
			String metricName = panel.getMetricTxtFIeld().getText();
			String rangeString = panel.getValidRangeTxtField().getText();
			ArrayList<IRange> validRanges = null;
			MetricType metricType = null;

			metricType = readMetricTYpe();
			if (metricType != null) {
				validRanges = parseValidRanges(rangeString, metricType);
				if (validRanges != null) {
					currentNewAttribute = new MeasuredAttribute(attributeName);

					Metric metric = new Metric(metricName, metricType);
					metric.setValidRanges(validRanges);
					currentNewAttribute.setMetric(metric);

					// Set the Worst and Best case for the metric
					setWorstBestCase(metric);

				} else {
					JOptionPane.showMessageDialog(panel,
							"Ranges are not Valid. Please correct them.");
				}

			}

		} else
			JOptionPane.showMessageDialog(panel.getParent(),
					"An Atribute with the same name already exists");

	}

	/**
	 * @param rangeString
	 * @param validRanges
	 * @param metricType
	 * @return
	 */
	private ArrayList<IRange> parseValidRanges(String rangeString,
			MetricType metricType) {
		ArrayList<IRange> validRanges = null;
		try {
			if (rangeString != null && !rangeString.equals("")) {
				validRanges = RangeParser.parseRange(rangeString, metricType);

			} else {
				validRanges = RangeParser.setDefaultValue(metricType);
			}
		} catch (ValidRangeFormatException e1) {
			e1.printStackTrace();
		}
		return validRanges;
	}

	/**
	 * @param metricType
	 * @return
	 */
	private MetricType readMetricTYpe() {
		MetricType metricType = null;
		// Set the Metric Type
		if (panel.getIntRadioButton().isSelected()) {
			metricType = MetricType.INTEGER;
		} else if (panel.getRealRadioButton().isSelected()) {
			metricType = MetricType.REAL;
		} else if (panel.getNotOrderedRadioButton().isSelected()
				|| panel.getOrderedRadioButton().isSelected()) {
			metricType = MetricType.DISCRETE;

		}
		return metricType;
	}

	/**
	 * @param metric
	 * 
	 */
	private void setWorstBestCase(Metric metric) {

		panel.showInternalWorstBestFrame(metric);

	}
}
